package starter

import (
	"fmt"
	"github.com/go-redis/redis/v8"
	"github.com/rs/zerolog/log"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"reflect"
	"strings"
	"time"
)
const (
	DBInParams = "gorm.DB"
	RedisInParams= "redis.Client"
	UnknownInParams = "in_params_field_config"
)

var InFuncMap = map[string]InFunc{
	DBInParams:funcDB,
	RedisInParams:funcClient,
	UnknownInParams:inParams,
}
func InParamMapFunc(name string) InFunc {
	if _,ok:= InFuncMap[name];ok {
		return InFuncMap[name]
	}else {
		return InFuncMap[UnknownInParams]
	}
}

func funcDB(k1 reflect.Value, value any) error {
	var val = value.(map[string]any)
	var connStr = fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
		val["user"],
		val["password"],
		val["host"],
		val["port"],
		val["name"],
	)
	db, err := gorm.Open(mysql.Open(connStr), &gorm.Config{})
	if err != nil {
		log.Printf("[info] gorm %s", err)
		panic("mysql连接失败")
	}
	k1.Set(reflect.ValueOf(db))
	return nil
}

func funcClient(k1 reflect.Value, value any) error {
	var val = value.(map[string]any)
	addr := fmt.Sprintf("%s:%d", val["host"], val["port"])
	client := redis.NewClient(&redis.Options{
		PoolSize:     val["max_active"].(int),
		MinIdleConns: val["max_idle"].(int),
		IdleTimeout:  2 * time.Second,
		Addr:         addr,                     // Redis服务器地址和端口
		Password:     val["password"].(string), // Redis密码（如果有的话）
		DB:           0,                        // Redis数据库索引
	})
	k1.Set(reflect.ValueOf(client))
	return nil
}

func inParams(k1 reflect.Value, value any) error {
	if !reflect.ValueOf(value).IsValid() {
		return   fmt.Errorf("1001,%s", "值不能为空")
	}
	var nk1 reflect.Value
	var nt1 reflect.Type
	vals := func(val any, typ reflect.StructField) any {
		return val.(map[string]any)[strings.ToLower(typ.Name)]
	}
	if k1.Kind() == reflect.Ptr {
		nk1 = reflect.New(k1.Type().Elem())
		nt1 = k1.Type().Elem()
	}
	for i := 0; i < nk1.Elem().NumField(); i++ {
		if _, ok := value.(map[string]any); !ok {
			return fmt.Errorf("1002,%s", "值类型不对")
		}
		if nk1.Elem().Field(i).Kind() != reflect.Ptr {
			nk1.Elem().Field(i).Set(reflect.ValueOf(vals(value, nt1.Field(i))))
		} else {
			inParams(nk1.Elem().Field(i), vals(value, nt1.Field(i)))
		}
	}
	k1.Set(nk1)
	return nil
}
